 /*******************************************************************************
  * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  * IBM Corporation - initial API and implementation
  *******************************************************************************/

 package org.eclipse.ui.internal.texteditor.quickdiff;

 import org.eclipse.core.runtime.Assert;

 import org.eclipse.jface.action.Action;

 import org.eclipse.jface.text.source.IAnnotationModel;
 import org.eclipse.jface.text.source.IAnnotationModelExtension;
 import org.eclipse.jface.text.source.IChangeRulerColumn;

 import org.eclipse.ui.IEditorInput;
 import org.eclipse.ui.texteditor.quickdiff.IQuickDiffReferenceProvider;
 import org.eclipse.ui.texteditor.quickdiff.ReferenceProviderDescriptor;
 import org.eclipse.ui.texteditor.IDocumentProvider;
 import org.eclipse.ui.texteditor.ITextEditor;
 import org.eclipse.ui.texteditor.ITextEditorExtension3;
 import org.eclipse.ui.texteditor.IUpdate;


 /**
  * Action to set the quick diff reference for the document displayed in the editor. An instance of
  * this class is created for every extension to the extension point <code>quickdiff.referenceprovider</code>, and for
  * every editor. It acts as a proxy; its <code>run</code> method installs the reference provider
  * specified by the extension with the quick diff differ on the current document.
  *
  * @since 3.0
  */
 public class ReferenceSelectionAction extends Action implements IUpdate {

     /** The editor we get the document from. */
     private ITextEditor fEditor= null;
     /** The descriptor of the managed extension. */
     private final ReferenceProviderDescriptor fDescriptor;
     /** The implementation of the extension, after it has been loaded. */
     private IQuickDiffReferenceProvider fProvider;

     /**
      * Creates a new instance that will lazily create the implementation provided by the extension.
      *
      * @param descriptor describes the extension.
      * @param editor the editor for which this action is created.
      */
     public ReferenceSelectionAction(ReferenceProviderDescriptor descriptor, ITextEditor editor) {
         super("", AS_RADIO_BUTTON); //$NON-NLS-1$
 setChecked(false);
         setEnabled(true);
         Assert.isLegal(descriptor != null);
         fDescriptor= descriptor;
         fEditor= editor;
         update();
     }

     /**
      * Creates an instance of the implementation provided by the extension, if none has been created
      * before. Otherwise, the cached implementation is returned.
      * @return The <code>IQuickDiffProviderImplementation</code> instance provided by the extension.
      */
     private IQuickDiffReferenceProvider getProvider() {
         if (fProvider == null) {
             fProvider= fDescriptor.createProvider();
         }
         return fProvider;
     }

     /*
      * @see org.eclipse.jface.action.IAction#run()
      */
     public void run() {

         DocumentLineDiffer differ= getDiffer(true); // create if needed, so the user does not have to toggle display when he selects a reference
 if (differ == null)
             return;

         if (fEditor instanceof ITextEditorExtension3) {
             ITextEditorExtension3 extension= (ITextEditorExtension3) fEditor;
             IQuickDiffReferenceProvider provider= getProvider();
             if (provider != null) {
                 provider.setActiveEditor(fEditor);
                 if (provider.isEnabled()) {
                     differ.setReferenceProvider(provider);
                     extension.showChangeInformation(true);
                     setEnabled(true);
                 } else
                     setEnabled(false);
             }
         }
     }

     /*
      * @see org.eclipse.ui.texteditor.IUpdate#update()
      */
     public void update() {
         /* two things happen here:
          * 1: checked state setting - if a provider is already installed, and its id matches
          * our id, we are in checked state.
          * 2: enablement - if the extending plugin has been loaded, we check the provider for
          * enablement and take it as our own.
          */
         setText(fDescriptor.getLabel());
         DocumentLineDiffer differ= getDiffer(false); // don't create it if we're not showing
 setChecked(false);
         if (differ != null) {
             IQuickDiffReferenceProvider provider= differ.getReferenceProvider();
             if (provider != null && provider.getId().equals(fDescriptor.getId())) {
                 setChecked(true);
             }
         }

         if (fDescriptor.isPluginLoaded()) {
             getProvider();
             if (fProvider == null) {
                 setEnabled(false);
             } else {
                 fProvider.setActiveEditor(fEditor);
                 setEnabled(fProvider.isEnabled());
             }
         } else {
             // optimistically enable it
 setEnabled(true);
         }
     }

     /**
      * Fetches the differ installed with the current editor's document's annotation model. If none
      * is installed yet, and <code>createIfNeeded</code> is true, one is created and attached to the
      * model.
      *
      * @param createIfNeeded when set to <code>true</code>, a new differ will be created if needed.
      * @return the differ installed with the annotation model, or <code>null</code>.
      */
     private DocumentLineDiffer getDiffer(boolean createIfNeeded) {
         // get annotation model
 if (fEditor == null)
             return null;

         IDocumentProvider provider= fEditor.getDocumentProvider();
         IEditorInput editorInput= fEditor.getEditorInput();
         if (provider == null || editorInput == null)
             return null;

         IAnnotationModel m= provider.getAnnotationModel(editorInput);
         IAnnotationModelExtension model= null;
         if (m instanceof IAnnotationModelExtension) {
             model= (IAnnotationModelExtension)m;
         } else {
             return null;
         }

         // get differ
 DocumentLineDiffer differ= (DocumentLineDiffer)model.getAnnotationModel(IChangeRulerColumn.QUICK_DIFF_MODEL_ID);

         // create if needed
 if (differ == null && createIfNeeded) {
             differ= new DocumentLineDiffer();
             model.addAnnotationModel(IChangeRulerColumn.QUICK_DIFF_MODEL_ID, differ);
         }

         return differ;
     }
 }

